<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>17.6.1-v-once</title>
</head>
<body>
    <!-- 参考例子 1 -->
    <section>
        <div v-once>{{ foo }}</div>
    </section>
</body>
    <script>
        /**
         * Vue.js 3 不仅会缓存内联事件处理函数，配合 v-once 还可实现对虚拟 DOM 的缓存
         * - 当编译器遇到 v-once 指令时，
         *    会利用我们上一节介绍的 cache 数组来缓存渲染函数的全部或者部分执行结果
         * 
         * v-once 指令能够从两个方面提升性能
         * - 避免组件更新时重新创建虚拟 DOM 带来的性能开销。
         *    因为虚拟 DOM 被缓存了，所以更新时无须重新创建
         * - 避免无用的 Diff 开销。
         *    这是因为被 v-once 标记的虚拟 DOM 树不会被父级 Block 节点收集
        */

        /**
         * 参考例子 1 
         * 被 v-once 指令标记，所以这段模板会被编译为
         * - 虚拟节点已经被缓存了，那么后续更新导致渲染函数重新执行时，会优先读取缓存的内容，而不会重新创建虚拟节点
         * - 更新前后的虚拟节点不会发生变化，因此也就不需要这些被缓存的虚拟节点参与 Diff 操作了
         * */ 
        function render(ctx, cache) {
            return (openBlock(), createBlock('section', null, [
                cache[1] || (cache[1] = createVNode("div", null, ctx.foo, 1 /* TEXT */))
            ]))
        }

        /**
         * 参考例子 1 
         * 在实际编译后的代码中经常出现下面这段内容
         * - setBlockTracking(-1) 函数调用，它用来暂停动态节点的收集
         *    换句话说，使用 v-once 包裹的动态节点不会被父级 Block 收集
         *    被 v-once 包裹的动态节点在组件更新时，自然不会参与 Diff 操作
         * 
         * */ 
         function render(ctx, cache) {
            return (openBlock(), createBlock('div', null, [
                cache[1] || (
                    setBlockTracking(-1), // 阻止这段 VNode 被 Block 收集
                    cache[1] = h("div", null, ctx.foo, 1 /* TEXT */),
                    setBlockTracking(1), // 恢复
                    cache[1] // 整个表达式的值
                )
            ]))
        }

        /**
         * v-once 指令通常用于不会发生改变的动态绑定中
         * - <div>{{ SOME_CONSTANT }}</div>
         * 
         * 为了提升性能，我们可以使用 v-once 来标记
         * - <div v-once>{{ SOME_CONSTANT }}</div>
         * 
         * 在组件更新时就会跳过这段内容的更新，从而提升更新性能
         * */ 



        
       

    </script>
</html>